


ТЕРМИНОЛОГИЯ
*****************************************************************************************************
Майерс. Эффективное использование с++. Терминология
*****************************************************************************************************
Объявление (Declaration) - сообщение компилятору имени и типа чего-либо, опуская некоторые детали
    extern int x;                      // объявл. объект
    std::size_t numbDigits(int number);// объявл. функции
    class Widget;                      // объявл. класса
    template<class T> class GraphNode; // объявл. шаблон

При помощи extern мы можем сказать компилятору, что определение находится где-то ещё.

Определение (Definition) - сообщение компилятору деталей, которые были опущени при объявлении.
Для объектов это место, где компилятор выделяет под него память, для ф. или шаблонов ф. - определение
содержит тело функции. В определении класса или шаблона класса перечесляются его члены.
    int x;                             // определение объекта
    int f() { return 0; }
    struct Widget
    {
        Widget() {}
    };
    template<class T>
    struct GraphNode
    {
        GraphNode() {}
    };

Инициализация - процесс присвоения объекту начального значения. Для пользовательских типов инициализация 
выполняется при помощи конструктора.
  
Конструктор по умолчанию - конструктор, который м.б. вызван без аргументов

Конструктор копирования - используется для инициализации объекта значением другого объекта такого же типа.
(Передача по значению означает вызов конструктора копирования)

Копирующий оператор присваивания (copy assignment operator) - копирует значение одного объекта в другой того же типа.
    Widget w3 = w2; // вызов конструктора копирования


*****************************************************************************************************
Майерс. Эффективное использование с++. совет 2. Предпочитайте const, enum, inline использованию #define
*****************************************************************************************************
Препроцессор подставляя вместо макроса его значение создаёт множество копий этого значения в объектном коде.
Использование константы не породит более одной копии.

При замене #define константами следует помнить:
  a. указатель, указывающий на что-то типа const сам следует сделать const
  const char* const name "Super name";
  b.  class GamePlayer 
      {
          static const int NumTurns = 5;  // объявление константы
          int scores[NumTurns];           // использование константы
      };
  Обычно с++ требует, чтобы было определение всего что используется.
  Исключение - объявление в классе константы, которая является статической и имеет встроенный тип.
  До тех пор, пока мы не попытаемся получить адрес этой константы её можно использовать без предоставления определения.
  Если же адрес требуется, то в файле реализации достаточно написать
      const int GamePlayer::NumTurns; // начальное значение задано в объявлении

  Старые компиляторы могут не поддерживать такой синтаксис, тогда можно использовать трюк с перечислением
      class GamePlayer 
      {
          enum { NumTurns = 5 };          // адрес перечисления получить нельзя
          int scores[NumTurns];           // использование константы
      };


*****************************************************************************************************
Майерс. Эффективное использование с++. совет 3. Везде, где только можно используйте const
*****************************************************************************************************
    const Rational operator*(const Rational &lhs, const Rational &rhs);

  Без const для возвращаемого объекта была бы возможна заведомо неверная конструкция

    (a * b) = c;

  Назначение модификатора const в объявлении метода - определить какие из методов можно использовать 
  для константного объекта. Так же он помогает сразу определить какие методы могут изменить объект.

  Константность бывает:
    - физическая;
    - логическая (mutable)


  Как избежать дублирования в константных и неконстантных функциях членах
  Имеет смысл испльзовать, когда константныя версия делает тоже самое, что и неконстантная.
  см пример const_member.h
  Важно, чтобы неконстантная версия была реализована через константную, а не наоборот


*****************************************************************************************************
Майерс. Эффективное использование с++. совет 4. Прежде чем использовать объекты, убедитесь, что они инициализированы.
*****************************************************************************************************
    В одних случаях объекты инициализируются в других нет, поэтому всегда следует убедиться,
    что объект инициализирован.
    Правила с++ оговаривают, что члены объекта инициализируются перед входом в тело конструктора!
    Т.е. внутри конструкта члены не инициализируются, а им присваиваются значения.
    Поэтому следует использовать списки инициализации вместро присваивания.
    Данные-члены, которые являются константами или ссылками, обязаны быть инициализированы.

    Если у класса данных слишком много, то можно инициализацию тех данных-членов, для которых присваивание работает так же
    как инициализация переместить в одну закрытую функцию, которую потом будут вызывать все конструкты.

    Порядок инициализации
    - базовые классы инициализируются раньше производных 
    - внутри класса члены-данные инициализируются в порядке перечисления 
      (объявления), даже если в списке инициализации они в другом порядке

    Объекты встроенных типов инициализировать следует вручную.

    Статический объект - существует с момента конструирования до конца работы программы.
    Размещённые в стеке или куче объекты статическими не являются.
    Статическими являются глобальные объекты, объекты объявленные в области действия пространства имён,
    объявленные с ключевым словом static внутри классов и функций, а так же в области действия отдельного
    файла с исходным кодом.
    Статические объекты, объявленные внутри функций - локальные статические объекты.
    Все остальные - нелокальные статические объекты
    Единица трансляции - исходный код, который порождает отдельный объектный файл.

    Относительный порядок инициализации статических нелокальных объектов, определённых в разных
    единицах трансляции, не определён.

    Проблема возникает, если есть 2 отдельно компилируемых исходных файла, каждый из которых содержит
    по крайней мере один нелокальный статический объект. Если инициализация нелокального статического
    объекта происходит в одной ед. трансл., а использование в другой ед. трансл и другим нелокальным
    статическим объектом, то 1ый объект может оказаться не инициализированным.

    Решение: каждый нелокальный статический объект надо поместить в функцию, и тем самым сделать его
    локальным. Функции будут возвращать ссылки на эти объекты. (Singleton)
    Локальные статически объекты инициализируются в первый раз, когда определение объекта встречается
    при вызове этой функции.
    
    Directory& getDir()
    {
        static Directory dir;
        return dir;
    }

    Но неконстантные статические объекты любого рода в многопоточных программах - проблема










ИТЕРАТОРЫ

Каждый стандартный контейнер поддерживает 4 типа итераторов:
 - iterator
 - const_iterator
 - reverse_iterator
 - const_reverse_iterator


*****************************************************************************************************
Майерс. Эффективное использование stl. совет 26. Старайтесь использовать iterator вместо остальных типов
*****************************************************************************************************

  Штука в том, что 
  - некоторым версиям insert и erase должен передаваться именно iterator
  - автомтическое преобразование const_iterator в iterator невозможно
  - преобразование reverse_iterator в iterator может требовать дополнительной регулировки итератора
  
*****************************************************************************************************
Майерс. Эффективное использование stl. совет 27. Используйте distance и advance для преобразования const_iterator в iterator
*****************************************************************************************************

  Пусть имеется const_iterator и требуется вставить элемент в позицию, на которую он указывает.
  Преобразование const_iterator в iterator при помощи const_cast делать нехорошо (скомпилится только для vector и string). 
  Для других контейнеров - нет, так как это вообще 2 разных класса.
  можно использовать конструкцию, описанную в example::inserting_using_const_iterator()

    std::advance(it, std::distance<decltype(c_it)>(it, c_it))

  Работает она за константное время для итераторов произвольного доступа и за линейное для итераторов других контейнеров.
  Следовательно, стоит по-возможности использовать iterator.


*****************************************************************************************************
Майерс. Эффективное использование stl. совет 28. Научитесь использовать функцию base()
*****************************************************************************************************

  Вставка делается в позицию перед указанным итератором.
  См. рис. reverse_iterator_base.png

    std::vector<int> v = { 1, 2, 3, 4, 5 };
    auto it = std::find(v.begin(), v.end(), 3);
    v.insert(it, 99);
    // result 1, 2, 99, 3, 4, 5

  Если у нас есть reverse_iterator rev_it, то для того, чтобы использовать его для вставки элемента нужно выполнить
  преобразование в тип iterator - rev_it.base(). Если до преобразования rev_it указывал на 3, то после будет иметь тип iterator и указывать на 4.
  Примеры: example::inserting();
           example::erasing();
           example::reverse_inserting();
           example::reverse_erasing();

*****************************************************************************************************
Майерс. Эффективное использование stl. совет 29. Рассмотрите возможность использования istreambuf_iterator при посимвольном вводе
*****************************************************************************************************
  
  Работа с istreambuf_iterator обычно быстрее чем работа через istream_iterator. Функции operator<< , от которых зависит работа istream_iterator
  производят форматный ввод, что замедляет работу программы.
  Примеры: example::istream_iterator_using()
           example::istreambuf_iterator_using()




ПРОСТРАНСТВА ИМЁН
*****************************************************************************************************

*****************************************************************************************************
Как объявить псевдоним пространства имён
    namespace dev = hardware::devices;
    dev::Device d;


Важно!!! При передаче функции параметра из какого-либо namespace компилятор включает этот namespace при
поиске имён функций, вызываемых в теле данной функции.

Советы по использованию пространств имён
  - Не стоит использовать импорт всего namespace
    using namespace std; // увеличивает риск конфликта имён
  - Нельзя использовать using в *.h файлах, т.к. они включают другие заголовочные файлы,
    для которых вряд ли предполагалось, что будет сделан using чего-то
  - Нельзя помещать объявления using или определения перед #include, т.к. то  что указано
    в using будет открыто для включённых заголовочных файлов, что вряд ли было задумано




ШАБЛОНЫ

Частичная специализация функций/методов НЕВОЗМОЖНА!









Всяческие наблюдения
1. Пусть есть 2 функции foo(...), куда передаются 2 константных или 2 неконстантных аргумента. Далее есть 2 объекта (константный и не константный).
Вызываем foo. Из 2х перегруженых функций будет вызвана та, что принимает 2 константных аргумента.

2.
struct base 
{ 
    virtual base* foo() { return this; } 
};
struct derived : base 
{ 
    derived* foo() override { return this; } // it's works
}; 

3.
вобщем, дело такое. когда вылетает эксэпшон, то объект копируется в любом случае. копируется с помощтю конструктора копирования в некую область.
затем из этой области он попадает в обработчик исключения. если обработчик перехватывает эксэпшон по значению, то происходит копирование объекта из этой области в обработчик.
если перехват по ссылке - то копирование не происходит, как при передаче аргумента по ссылке в функцию.
поэтому, если перехватываешь по значению, то вызывается конструктор копирования,
то есть если перехватываешь объект базового класса, то и вызывается конструктор копирования базового класса, поэтому вся "производность" уходит
как я понял, срезка, это когда мы теряем часть инфы, из за того, что передаём по значению через базовый класс
По указателю кидать исключения не стоит, так как:
аа, блин, я понял, там же, свёртка стека происходит.. или как там это называется..
и все локальные объекты полюбому сдохнут
именно так
а если будет копирование, т.е. throw b; то всё будет, как ты написала
4.
 есть у тебя огромная струутура, например, и ты хочешь её всю проинициализировать нулями
[13:59:59] Lera Kishmar: ога
[14:00:16] Lera Kishmar: можно написать TestStruct a = {};

5. http://hashcode.ru/questions/242499/c-%D0%B2%D1%8B%D0%B7%D0%BE%D0%B2-%D0%BA%D0%BE%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D0%BE%D1%80%D0%B0-%D0%B1%D0%B5%D0%B7-%D1%81%D0%BA%D0%BE%D0%B1%D0%BE%D0%BA

6. Для того, чтобы в коде отключить предупреждения (g++) можно использовать следующие директивы

#pragma GCC diagnostic push // save warning state
#pragma GCC diagnostic ignored "-Wnarrowing"
 // some code that does narrowing warning - for this code warning will supressed
#pragma GCC diagnostic pop  // restore warning state
 // some code that does narrowing warning - for this code compiler generate warning

7. Compound statement(block) состоит из 0 или более statement заключённых в скобки {}. Compound statement может быть использовано где угодно, где используется statement.

8. do/while trick in macro - see exceptions.h in stl-exmaple project

9. Фокус с инлайн методами
inline_method::print() в примерах
Дело в том, что компиляция происходит модульно. Каждый cpp файл компилится отдельно, и чтобы сказать компилятору, что мы
        хотим задействовать некий метод мы используем предварительное объявление - подключение заголовочных файлов.
        А уже при линковке происходит разрешение зависимостей (названию вызванного метода сопосталяется реальный адрес этого метода из другого объектного файла).
        Если метод оказался действительно встроенным, то у него нет адреса и поэтому линковщик будет ругаться - undefined reference to method.
        Решение - реализовывать метод в заголовочном файле, чтобы при его подключении в cpp у компилятора был доступ к телу функции

10. shared_ptr and forward declaration
You need at least a forward declaration for T for every mention of shared_ptr<T>.
Only if you use unary shared_ptr::operator* and shared_ptr::operator->, the full thing is needed. Under the hood, shared_ptr uses a mix of compiletime- and runtime-polymorphism, making this possible.


11. Фокус-покус. Определить, что число является степенью двойки

число 16  двоичный код 1 0 0 0 0
число 15  двоичный код 0 1 1 1 1

bool is_pow_2(int x)
{
    return (x & (x - 1)) == 0x0 ? true : false;
    // если x - ноль, то результат true - вырожденный случай
    // return (x & (x - 1)) == 0x0;
}

12. Почему статический метод не может быть константным
When you apply the const qualifier to a nonstatic member function, it affects the this pointer. 
For a const-qualified member function of class C, the this pointer is of type C const*, 
whereas for a member function that is not const-qualified, the this pointer is of type C*.

A static member function does not have a this pointer (such a function is not called on a particular instance of a class),
so const qualification of a static member function doesn't make any sense.
Если своими словами и по русски у статического метода не может быть указателя this (т.к. нет объекта), который бы можно было привести к константному.

13. 
I've seen default used next to function declarations in a class. What does it do?
class C 
{
  C(const C&) = default;
  C(C&&) = default;
  C& operator=(const C&) & = default;
  C& operator=(C&&) & = default;
  virtual ~C() { }
};
It's a new C++11 feature.

It means that you want to use the compiler-generated version of that function, so you don't need to specify a body.

You can also use = delete to specify that you don't want the compiler to generate that function automatically.

With the introduction of move constructors and move assignment operators, the rules for when automatic versions of constructors, destructors and assignment operators are generated has become quite complex. Using = default and = delete makes things easier as you don't need to remember the rules: you just say what you want to happen.

14.
Introduction: This answer tries to focus on the basic aspects in current C++03 of dependent names, as well as the typename and template disambiguation keywords. Other aspects should be handled in another answer or another FAQ entry.

In order to parse a C++ program, you need to know for certain names whether they name types or non-types. The following should suffice as an example

t * f;
How should this be parsed? Usually, for simple languages for parsing you don't need to know the meaning of a name but can just grammatically analyze the input and then create a parse tree out of it. In C++, the above can yield different parse-trees depending on what t means. If it's a type, then it will be parsed as a declaration (and semantically it will declare f as a pointer variable). However if it's a non-type, it will be parsed as an expression. So the draft Standard says at 3.7

Some names denote types or templates. In general, whenever a name is encountered it is necessary to determine whether that name denotes one of these entities before continuing to parse the program that contains it. The process that determines this is called name lookup.

This however presents a problem in templates: How will you find out what a name t::x refers to, if t refers to a template type parameter? x could be a static data member or member function (non-type) or could equally well be a nested class or typedef.

Dependencies

In template declarations some constructs have different meanings depending on what template arguments you use to instantiate the template: Expressions may have different types or values, variables may have different types or function calls might end up calling different functions. Such constructs are generally said to depend on template parameters.

The Standard defines precisely the rules by whether a construct is dependent or not. It separates them into logically different groups: One catches types, another catches expressions. Expressions may depend by their value and/or their type. So we have, with typical examples appended

Dependent types (e.g: a type template parameter T)
Value-dependent expressions (e.g: a non-type template parameter N)
Type-dependent expressions (e.g: a cast to a type template parameter (T)0)
Most of the rules are intuitive and are built up recursively: For example, a type constructed as T[N] is a dependent type if N is a value-dependent expression or T is a dependent type. The details of this can be read in section 14.6.2/1 for dependent types, 14.6.2.2 for type-dependent expressions and 14.6.2.3 for value-dependent expressions.

Dependent names

Now of all the constructs that denote dependent types or expressions, a subset of them represent names. A name can take different forms - the draft Standard says

A name is a use of an identifier (2.11), operator-function-id (13.5), conversion-function-id (12.3.2), or template-id (14.2) that denotes an entity or label (6.6.4, 6.1)

An identifier is just a plain sequence of characters / digits, while the next two are the operator + and operator type form. The last form is template-name <argument list>. All these are names, and by conventional use in the Standard, a name can also include qualifiers that say what namespace or class a name should be looked up in.

A value dependent expression 1 + N is not a name, but N is. The subset of all dependent constructs that are names is called dependent name. Function names, however, may have different meaning in different instantiations of a template, but unfortunately are not caught by this general rule.

Dependent function names

Not primarily a concern of this article, but still worth mentioning: Function names are an exception that are handled separately. An identifier function name is dependent not by itself, but by the type dependent argument expressions used in a call. In the example f((T)0), f is a dependent name. In the Standard, this is specified at 14.6.2/1.

The "typename" keyword

Let's get back to our initial problem - how can we parse t::x * f;? The answer is: In this case, we decide how the compiler should parse this. If t::x is a dependent name, then we need to prefix it by typename to tell the compiler to parse it in a certain way. The Standard says at 14.6/2

A name used in a template declaration or definition and that is dependent on a template-parameter is assumed not to name a type unless the applicable name lookup finds a type name or the name is qualified by the keyword typename.

There are many dependent names for which typename is not necessary, because the compiler can, with the applicable name lookup in the template definition, figure out how to parse a construct itself - for example with T *f;, when T is a type template parameter. But for t::x * f; to be a declaration must be written as typename t::x *f;. If you omit the keyword and the name is taken to be a non-type, but when instantiation finds it denotes a type, the usual error messages are emitted by the compiler. Since whether it's a type or not determines parsing, you will often get parser errors already at definition time

// t::x is taken as non-type, but as an expression the following misses an
// operator between the two names or a semicolon separating them.
t::x f;
The syntax allows typename only before qualified names - it is therefor taken as granted that unqualified names are always known to refer to types if they do so.

A similar gotcha exists for names that denote templates, as hinted at by the introductory text.

The "template" keyword

Have you ever wondered how the following is parsed?

boost::function< int() > f;
Possibly not, because it might look obvious to a human reader. Not so for the compiler. Imagine the following arbitrary definition of boost::function and f

namespace boost { int function = 0; }
int main() { 
  int f = 0;
  boost::function< int() > f; 
}
That's actually a valid expression! It compares boost::function with zero (int()), and then compares the resulting bool against f. However as you might well know, boost::function in real life is a template, so the compiler knows (14.2/3)

After name lookup (3.4) finds that a name is a template-name, if this name is followed by a <, the < is always taken as the beginning of a template-argument-list and never as a name followed by the less-than operator

Now we are back to the same problem as with typename. What if we can't know yet whether the name is a template when parsing the code? We will need to insert template immediately before the template name, as specified by 14.2/4. This looks like

t::template f<int>(); // call a function template
Template names can not only occur after a :: but also after a -> or . in a class member access. You need to insert the keyword there too

this->template f<int>(); // call a function template
Additional notes and examples

In enough cases we need both of typename and template. Your code should look like the following

template <typename T, typename Tail>
struct UnionNode : public Tail {
    // ...
    template<typename U> struct inUnion {
        typedef typename Tail::template inUnion<U> dummy;
    };
    // ...
};
The keyword template doesn't always have to appear in the last part of a name. It can appear in the middle before a class name that's used as a scope, like in the following example

typename t::template iterator<int>::value_type v;
In some cases, the keywords are forbidden, as detailed below

On the name of a dependent base class you are not allowed to write typename. It's assumed that the name given is a class type name. This is true for both names in the base-class list and the constructor initalizer list

 template <typename T>
 struct derive_from_Has_type : /* typename */ SomeBase<T>::type 
 { };
In using-declarations it's not possible to use template after the last ::, and the C++ committee said not to work on a solution.

 template <typename T>
 struct derive_from_Has_type : SomeBase<T> {
    using SomeBase<T>::template type; // error
    using typename SomeBase<T>::type; // typename *is* allowed
 };
In current C++, typename and template is disallowed anywhere outside a template, including explicit (full) template specializations. In C++0x, this will be allowed for both template and typename.

 template <> struct derive_from_Has_type<int> { 
   typedef Int<int>::template Has_Type<int> type; // error
 };

14.
std::string get_string()
{
    return "xxx";
}
int main(int argc, char *argv[])
{
    std::string str = "x";

    auto s = get_string();
    str.swap(get_string()); // не компилится  trying to pass an rvalue (e.g. a temporary) to a function that requires an lvalue
    str.swap(s);            // компилится
    return 0;
}

ВОПРОСЫ

есть тупой класс
struct A
{
    std::vector<int> vec_;
    int size_;
};
если для этого класса не создать вручну. конструктор копирования, то тот который сгенерится автоматически сделает копию данного класса?
Ответ: да. Тогда в каком случае сгенерированный автоматически конструктор даст сбой? Какие условия должны выполняться, чтобы автоматически сгенерированный копирующий конструктор работал корректно?





